package asruby.lang
{
import asruby.Ruby;
import asruby.asupport.RuntimeHelpers;
import asruby.evaluator.ASTInterpreter;
import asruby.runtime.Arity;
import asruby.runtime.Block;
import asruby.runtime.CallType;
import asruby.runtime.CallbackFactory;
import asruby.runtime.ClassIndex;
import asruby.runtime.IRubyObject;
import asruby.runtime.MethodIndex;
import asruby.runtime.ThreadContext;
import asruby.runtime.VariableTableEntry;
import asruby.runtime.Visibility;
import asruby.runtime.buildin.InstanceVariables;
import asruby.runtime.buildin.InternalVariables;
import asruby.runtime.buildin.Variable;
import asruby.runtime.component.VariableEntry;
import asruby.runtime.methods.DynamicMethod;
import asruby.util.IdUtil;
import asruby.util.TypeConverter;

import flash.utils.Dictionary;
	
public class RubyObject implements IRubyObject { // InstanceVariables , InternalVariables {
    
    public static var NULL_ARRAY: Array= new Array();
    
    /* private function RubyObject() {}; */
    // An instance that never equals any other instance
    //public static var NEVER: IRubyObject = new RubyObject();
    
    // The class of this object
    protected var metaClass: RubyClass;
    protected var metaClassName: String;
	
    /**
     * The variableTable contains variables for an object, defined as:
     * <ul>
     * <li> instance variables
     * <li> class variables (for classes/modules)
     * <li> internal variables (such as those used when marshaling RubyRange and RubyException)
     * </ul>
     * 
     * Constants are stored separately, see {@link RubyModule}. 
     * 
     */
    protected var variableTable: Array;
    protected var variableTableSize: int;
    protected var variableTableThreshold: int;

    private var dataStruct: Object;

    protected var flags:int; 
    public static var ALL_F:int = -1;
    public static var FALSE_F: int = 1 << 0;
    public static var NIL_F: int = 1 << 1;
    public static var FROZEN_F: int = 1 << 2;
    public static var TAINTED_F: int = 1 << 3;

    public static var FL_USHIFT: int = 4;
    
 	public static var USER0_F:int = (1<<(FL_USHIFT+0));
    public static var USER1_F:int = (1<<(FL_USHIFT+1));
    public static var USER2_F:int = (1<<(FL_USHIFT+2));
    public static var USER3_F:int = (1<<(FL_USHIFT+3));
    public static var USER4_F:int = (1<<(FL_USHIFT+4));
    public static var USER5_F:int = (1<<(FL_USHIFT+5));
    public static var USER6_F:int = (1<<(FL_USHIFT+6));
    public static var USER7_F:int = (1<<(FL_USHIFT+7));

    public final function  setFlag(flag: int, set: Boolean): void {
        if (set) {
            flags |= flag;
        } else {
            flags &= ~flag;
        }
    }
    
    public final function  getFlag(flag: int): Boolean {
        return (flags & flag) != 0;
    }
    
    /** standard path for object creation 
     * 
     */
   	public function  RubyObject(runtime: Ruby, metaClass: RubyClass, useObjectSpace:Boolean=true) {
       	this.metaClass = metaClass;
        if ( metaClass != null) {
            metaClassName = metaClass.classId;
        }

/*         if (runtime.isObjectSpaceEnabled()) {
            //assert runtime.isObjectSpaceEnabled();
            runtime.getObjectSpace().push(this);
        } */

        // FIXME are there objects who shouldn't be tainted?
        // (mri: OBJSETUP)
        if (runtime.getSafeLevel() >= 3) flags |= TAINTED_F;
    }
    
    public static function  createObjectClass(runtime: Ruby, objectClass: RubyClass): RubyClass {
        objectClass.index = ClassIndex.OBJECT;

        var callbackFactory: CallbackFactory = runtime.callbackFactory(RubyObject);
        objectClass.defineFastPrivateMethod("initialize", callbackFactory.getFastMethod0("initialize"));

        return objectClass;
    }
    
    public static var OBJECT_ALLOCATOR = function (runtime: Ruby, klass: RubyClass): IRubyObject {
        return new RubyObject(runtime, klass);
    }

/*     public function  attachToObjectSpace(): void {
        getRuntime().getObjectSpace().add(this);
    } */
    
    /**
     * This is overridden in the other concrete Java builtins to provide a fast way
     * to determine what type they are.
     */
    public function  getNativeTypeIndex(): int {
        return ClassIndex.OBJECT;
    }

    public function  isModule(): Boolean {
        return false;
    }
    
    public function  isClass(): Boolean {
        return false;
    }

    /*
     *  Is object immediate (def: Fixnum, Symbol, true, false, nil?).
     */
    public function  isImmediate(): Boolean {
    	return false;
    }

    /** rb_make_metaclass
     *
     */
    public function  makeMetaClass(superClass: RubyClass): RubyClass {
        var klass: MetaClass = new MetaClass(getRuntime(), superClass); // rb_class_boot
        setMetaClass(klass);

        klass.setAttached(this);
        klass.setMetaClass(superClass.getRealClass().getMetaClass());

        return klass;
    }

	    
    public  function getJavaClass():Class{
   		//return IRubyObject.class;
   		return null; 		
 	}  
    public static function  puts(obj: Object): void {
        trace(obj.toString());
    }

    /**
     * This method is just a wrapper around the Ruby "==" method,
     * provided so that RubyObjects can be used as keys in the Java
     * HashMap object underlying RubyHash.
     */
    public function  equals(other: Object): Boolean {
        return other == this || 
                other instanceof IRubyObject && 
                callMethod6(getRuntime().getCurrentContext(), MethodIndex.EQUALEQUAL, "==", IRubyObject(other)).isTrue();
    }

    public function  toString(): String {
        return RuntimeHelpers.invoke7(getRuntime().getCurrentContext(), this, MethodIndex.TO_S, "to_s", RubyObject.NULL_ARRAY).toString();
    }

    /** Getter for property ruby.
     * @return Value of property ruby.
     */
    public final function  getRuntime(): Ruby {
        return getMetaClass().getClassRuntime();
    }

    /**
     * if exist return the meta-class else return the type of the object.
     *
     */
    public final function  getMetaClass(): RubyClass {
        var mc:RubyClass;
        if ((mc = metaClass) != null) return mc;
        if (metaClassName != null) {
            // this should only happen when we're persisting objects, so go after getCurrentInstance directly
           	metaClass = Ruby.getCurrentInstance().getClass(metaClassName);
        }
        return metaClass;
    }

    public function  setMetaClass(metaClass: RubyClass): void {
        this.metaClass = metaClass;
        metaClassName = metaClass.classId;
/*         if (Ruby.RUNTIME_THREADLOCAL && metaClass != null) {
            metaClassName = metaClass.classId;
        } */
    }

    /**
     * Gets the frozen.
     * @return Returns a Boolean
     */
    public function  isFrozen(): Boolean {
        return (flags & FROZEN_F) != 0;
    }

    /**
     * Sets the frozen.
     * @param frozen The frozen to set
     */
    public function  setFrozen(frozen: Boolean): void {
        if (frozen) {
            flags |= FROZEN_F;
        } else {
            flags &= ~FROZEN_F;
        }
    }

    /**
     * Gets the taint.
     * @return Returns a Boolean
     */
    public function  isTaint(): Boolean {
        return (flags & TAINTED_F) != 0; 
    }

    /**
     * Sets the taint.
     * @param taint The taint to set
     */
    public function  setTaint(taint: Boolean): void {
        if (taint) {
            flags |= TAINTED_F;
        } else {
            flags &= ~TAINTED_F;
    }
    }

    public final function  isNil(): Boolean {
        return (flags & NIL_F) != 0;
    }

    public final function  isTrue(): Boolean {
        return (flags & FALSE_F) == 0;
    }

    public final function  isFalse(): Boolean {
        return (flags & FALSE_F) != 0;
    }

    public function  respondsTo(name: String): Boolean {
        if(getMetaClass().searchMethod("respond_to?") == getRuntime().getRespondToMethod()) {
            return getMetaClass().isMethodBound(name, false);
        } else {
            return callMethod2(getRuntime().getCurrentContext(),"respond_to?",getRuntime().newSymbol(name)).isTrue();
        }
    }

    // rb_singleton_class
    // Note: this method is specialized for RubyFixnum, RubySymbol, RubyNil and RubyBoolean   
    public function  getSingletonClass(): RubyClass {
        var klass:RubyClass;
        
        if (getMetaClass().isSingleton() && getMetaClass().getAttached() == this) {
            klass = getMetaClass();
        } else {
            klass = makeMetaClass(getMetaClass());
        }
        
        klass.setTaint(isTaint());
        if (isFrozen()) klass.setFrozen(true);
        
        return klass;
    }
/*    
    // rb_singleton_class_clone

    protected function getSingletonClassClone():RubyClass {
       var klass: RubyClass = getMetaClass();

       if (!klass.isSingleton()) return klass;

       var clone: MetaClass = new MetaClass(getRuntime());
       clone.flags  = flags;

       if (this instanceof RubyClass) {
           clone.setMetaClass(clone);
       } else {
           clone.setMetaClass(klass.getSingletonClassClone());
       }

       clone.setSuperClass(klass.getSuperClass());

       if (klass.hasVariables()) {
           clone.syncVariables(klass.getVariableArray());
       }

       klass.cloneMethods(clone);

       clone.getMetaClass().setAttached(clone);

       clone.setAttached(klass.getAttached());

       return clone;
    }

    // init_copy
    private static function  initCopy(clone: IRubyObject, original: RubyObject): void {
        //assert !clone.isFrozen() : "frozen object (" + clone.getMetaClass().getName() + ") allocated";

        //original.copySpecialInstanceVariables(clone);

        if (original.hasVariables()) {
            clone.syncVariables(original.getVariableArray());
        }

        // FIXME: finalizer should be dupped here
        clone.callMethod2(clone.getRuntime().getCurrentContext(), "initialize_copy", original);
    }

    // OBJ_INFECT
    public function  infectBy(obj: IRubyObject): IRubyObject {
        if (obj.isTaint()) setTaint(true);
        return this;
    }
*/
    public function  callSuper(context: ThreadContext, args: Array, block: Block): IRubyObject {
        var klazz: RubyModule = context.getFrameKlazz();

        var superClass: RubyClass = RuntimeHelpers.findImplementerIfNecessary(getMetaClass(), klazz).getSuperClass();
        
        //assert superClass != null : "Superclass should always be something for " + klazz.getBaseName();

        return RuntimeHelpers.invokeAs(context, superClass, this, context.getFrameName(), args, CallType.SUPER, block);
    }    

    public function  callMethod(context: ThreadContext, name: String): IRubyObject {
        return RuntimeHelpers.invoke5(context, this, name, RubyObject.NULL_ARRAY, null, Block.NULL_BLOCK);
    }
    public function  callMethod2(context: ThreadContext, name: String, arg: IRubyObject): IRubyObject {
        return RuntimeHelpers.invoke6(context, this, name, arg, CallType.FUNCTIONAL, Block.NULL_BLOCK);
    }
    public function  callMethod3(context: ThreadContext, name: String, args: Array): IRubyObject {
        return RuntimeHelpers.invoke5(context, this, name, args, CallType.FUNCTIONAL, Block.NULL_BLOCK);
    }
    public function  callMethod4(context: ThreadContext, name: String, args: Array, block: Block): IRubyObject {
        return RuntimeHelpers.invoke5(context, this, name, args, CallType.FUNCTIONAL, block);
    }
    public function  callMethod5(context: ThreadContext, methodIndex: int, name: String): IRubyObject {
        return RuntimeHelpers.invoke8(context, this, methodIndex, name, RubyObject.NULL_ARRAY, null, Block.NULL_BLOCK);
    }
    public function  callMethod6(context: ThreadContext, methodIndex: int, name: String, arg: IRubyObject): IRubyObject {
        return RuntimeHelpers.invoke8(context, this, methodIndex,name,[arg],CallType.FUNCTIONAL, Block.NULL_BLOCK);
    }

    public function callInit(args: Array, block: Block): void {
        callMethod4(getRuntime().getCurrentContext(), "initialize", args, block);
    }

    //rb_to_id
    public function  asJavaString(): String {
        var asString: IRubyObject = checkStringType();
        if(!asString.isNil()) return asString.asJavaString();
        throw getRuntime().newTypeError(inspect().toString() + " is not a symbol");
    }

    public function  convertToArray(): RubyArray {
        return RubyArray(TypeConverter.convertToType2(this, getRuntime().getArray(), MethodIndex.TO_ARY, "to_ary"));
    }

    public function  convertToHash(): RubyHash {
        return RubyHash(TypeConverter.convertToType2(this, getRuntime().getHash(), MethodIndex.TO_HASH, "to_hash"));
    }
    
    public function  convertToFloat(): RubyFloat {
        return RubyFloat(TypeConverter.convertToType2(this, getRuntime().getFloat(), MethodIndex.TO_F, "to_f"));
    }

    public function  convertToInteger(): RubyInteger {
        return convertToInteger2(MethodIndex.TO_INT, "to_int");
    }

    public function  convertToInteger2(convertMethodIndex: int, convertMethod: String): RubyInteger {
        var val: IRubyObject = 
        	TypeConverter.convertToType(this, getRuntime().getInteger(), convertMethodIndex, convertMethod, true);
        if (!(val instanceof RubyInteger)) 
        	throw getRuntime().newTypeError(getMetaClass().getName() + "#" + convertMethod + " should return Integer");
        return RubyInteger(val);
    }

    public function  convertToString(): RubyString {
        return RubyString(TypeConverter.convertToType2(this, getRuntime().getString(), MethodIndex.TO_STR, "to_str"));
    }
    
    public final function  convertToType(target: RubyClass, convertMethodIndex: int): IRubyObject {
        return TypeConverter.convertToType2(this, target, convertMethodIndex, MethodIndex.NAMES.get(convertMethodIndex));
    }

    /** rb_obj_as_string
     */
    public function  asString(): RubyString {
        var str: IRubyObject = 
        	RuntimeHelpers.invoke7(getRuntime().getCurrentContext(), this, MethodIndex.TO_S, "to_s", RubyObject.NULL_ARRAY);
        
        if (!(str instanceof RubyString)) return RubyString(anyToString());
        if (isTaint()) str.setTaint(true);
        return RubyString(str);
    }
    
    /** rb_check_string_type
     *
     */
    public function  checkStringType(): IRubyObject {
        var str: IRubyObject = TypeConverter.convertToTypeWithCheck(this, getRuntime().getString(), MethodIndex.TO_STR, "to_str");
        if(!str.isNil() && !(str instanceof RubyString)) {
           	str = getRuntime().newString("");
        }
        return str;
    }

    /** rb_check_array_type
    *
    */    
    public function checkArrayType(): IRubyObject {
        return TypeConverter.convertToTypeWithCheck(this, getRuntime().getArray(), MethodIndex.TO_ARY, "to_ary");
    }

    /** specific_eval
     *
     *
    public function  specificEval(context: ThreadContext, mod: RubyModule, args: Array, block: Block): IRubyObject {
         if (block.isGiven()) {
            if (args.length > 0) throw getRuntime().newArgumentError(args.length, 0);

            return yieldUnder(context, mod, [this], block);
        } 

        if (args.length == 0) {
            throw getRuntime().newArgumentError("block not supplied");
        } else if (args.length > 3) {
            var lastFuncName: String = context.getFrameName();
            throw getRuntime().newArgumentError(
                "wrong # of arguments: " + lastFuncName + "(src) or " + lastFuncName + "{..}");
        }
        
        if (ruby.getSecurityLevel() >= 4) {
                Check_Type(argv[0], T_STRING);
        } else {
                Check_SafeStr(argv[0]);
        }
        
        // We just want the TypeError if the argument doesn't convert to a String (JRUBY-386)
        args[0] = args[0].convertToString();

        var file: IRubyObject = args.length > 1 ? args[1] : getRuntime().newString("(eval)");
        var line: IRubyObject = args.length > 2 ? args[2] : RubyFixnum.one(getRuntime());

        var savedVisibility: Visibility = context.getCurrentVisibility();
        context.setCurrentVisibility(Visibility.PUBLIC);
        try {
            return evalUnder(context, mod, args[0], file, line);
        } finally {
            context.setCurrentVisibility(savedVisibility);
        }
        return null;
    }

    public function evalUnder(context:ThreadContext, under:RubyModule, src:IRubyObject, file:IRubyObject, line:IRubyObject): IRubyObject {
        return under.executeUnder(context, new Callback ( 
            function  execute(self: IRubyObject, args: Array, block: Block): IRubyObject {
                var source: IRubyObject = args[1];
                var filename: IRubyObject = args[2];
                // Line numbers are zero-based so we subtract one
                var lineNumber:int = (args[3].convertToInteger().getLongValue() - 1);

                return ASTInterpreter.evalSimple(context, args[0], source, 
                        filename.convertToString().toString(), lineNumber);
            }
			,
            function getArity(): Arity {
                return Arity.optional();
            }
        ), [ this, src, file, line ], Block.NULL_BLOCK);
    }
 
    private function  yieldUnder(context:ThreadContext, under:RubyModule, args:Array, block:Block): IRubyObject {
        return under.executeUnder(context, new Callback(
            function execute(self: IRubyObject, args: Array, block: Block): IRubyObject {
                var savedVisibility: Visibility = block.getBinding().getVisibility();

                block.getBinding().setVisibility(Visibility.PUBLIC);
                try {
                    var valueInYield:IRubyObject;
                    var aValue:Boolean;
                    if (args.length == 1) {
                        valueInYield = args[0];
                        aValue = false;
                    } else {
                        valueInYield = RubyArray.newArray(getRuntime(), args);
                        aValue = true;
                    }
                    
                    // FIXME: This is an ugly hack to resolve JRUBY-1381; I'm not proud of it
                    block = block.cloneBlock();
                    block.getBinding().setSelf(RubyObject);
                    block.getBinding().getFrame().setSelf(RubyObject);
                    // end hack
                    
                    return block.yield(context, valueInYield, RubyObject, context.getRubyClass(), aValue);
                    //TODO: Should next and return also catch here?
                } catch (bj:RubyException) {
                    return bj.getValue();
                } finally {
                    block.getBinding().setVisibility(savedVisibility);
                }
            }
			,
            function  getArity(): Arity {
                return Arity.optional();
            }
        ), args, block);
    }
 */
    // Methods of the Object class (rb_obj_*):

    /** rb_obj_equal
     *
     */
    //@JRubyMethod(name = "==var required: " = 1)
    public function  op_equal(context: ThreadContext, obj: IRubyObject): IRubyObject {
        return this == obj ? getRuntime().getTrue() : getRuntime().getFalse();
    }
    
    //@JRubyMethod(name = var required: "equal?" = 1)
    public function  equal_p(obj: IRubyObject): IRubyObject {
        return this == obj ? getRuntime().getTrue() : getRuntime().getFalse();
    }

    /** method used for Hash key comparison (specialized for String, Symbol and Fixnum)
     * 
     */
    public function  eql(other: IRubyObject): Boolean {
        return callMethod6(getRuntime().getCurrentContext(), MethodIndex.EQL_P, "eql?", other).isTrue();
    }
    
    //@JRubyMethod(name = var required: "eql?" = 1)
    public function  eql_p(obj: IRubyObject): IRubyObject {
        return this == obj ? getRuntime().getTrue() : getRuntime().getFalse();
    }
    
    /** rb_equal
     * 
     */
    //@JRubyMethod(name = "===var required: " = 1)
    /* public function  op_eqq(context: ThreadContext, other: IRubyObject): IRubyObject {
        return getRuntime().newBoolean(this == other || callMethod(context, MethodIndex.EQUALEQUAL, "==",other).isTrue());
    } */
    public function op_eqq(context:ThreadContext, other:IRubyObject):Boolean{
    	return null;
    }
    protected static function equalInternal(context:ThreadContext, that:IRubyObject, other:IRubyObject):IRubyObject {
        if (that == other) return that.getRuntime().getTrue();
        return that.callMethod6(context, MethodIndex.EQUALEQUAL, "==", other);
    }

    protected static function eqlInternal(context:ThreadContext , that:IRubyObject , other:IRubyObject ):Boolean {
        if (that == other) return true;
        return that.callMethod6(context, MethodIndex.EQL_P, "eql?", other).isTrue();
    }

    /** rb_obj_init_copy
     * 
     */
    //@JRubyMethod(name = "initialize_copy", required = var visibility: 1 = Visibility.PRIVATE)
    public function  initialize_copy(original: IRubyObject): IRubyObject {
	    if (this == original) return this;
	    //checkFrozen();

        if (getMetaClass().getRealClass() != original.getMetaClass().getRealClass()) {
            throw getRuntime().newTypeError("initialize_copy should take same class object");
	    }

	    return this;
	}

    /**
     * respond_to?( var includePriv: aSymbol=false ) -> true or false
     *
     * Returns true if this object responds to the given method. Private
     * methods are included in the search only if the optional second
     * parameter evaluates to true.
     *
     * @return true if this responds to the given method
     * FIXME: !!! For some reason MRI shows the arity of respond_to? as -1, when it should be -2; that's why this is rest instead of var optional: required = 1
     */
    //@JRubyMethod(name = var rest: "respond_to?" = true)
    public function respond_to_p(args: Array): RubyBoolean {
        var name: String = args[0].asJavaString();
        var includePrivate: Boolean = args.length > 1 ? args[1].isTrue() : false;

        return getRuntime().newBoolean(getMetaClass().isMethodBound(name, !includePrivate));
    }

    /** Return the internal id of an object.
     *
     * <i>CRuby function: rb_obj_id</i>
     * FIXME: Should this be renamed to match its ruby name?
     */
    //@JRubyMethod(name = {"object_id", "__id__"})
    public function id(): IRubyObject {
    	return getRuntime().newFixnum(0);
        //return getRuntime().newFixnum(getRuntime().getObjectSpace().idOf(this));
    }

    /** rb_obj_id_obsolete
     * 
     */
    //@JRubyMethod(name = "id")
    public function  id_deprecated(): IRubyObject {
        getRuntime().getWarnings().warn1(RubyWarnings.DEPRECATED_METHOD, 
        	"Object#id will be deprecated; use Object#object_id", "Object#id", "Object#object_id");
        return id();
    }
    
    //@JRubyMethod(name = "hash")
    public function  hash(): RubyFixnum {
        return getRuntime().newFixnum(super.hashCode());
    }

    public function  hashCode(): int {
        var hashValue: IRubyObject = callMethod5(getRuntime().getCurrentContext(), MethodIndex.HASH, "hash");
        
        if (hashValue instanceof RubyFixnum) return RubyNumeric.fix2Number(hashValue); 
        
        return super.hashCode();
    }

    /** rb_obj_type
     *
     */
    //@JRubyMethod(name = "class")
    public function  type(): RubyClass {
        return getMetaClass().getRealClass();
    }
/*
    //@JRubyMethod(name = "type")
    public function  type_deprecated(): RubyClass {
        getRuntime().getWarnings().warn2(RubyWarnings.DEPRECATED_METHOD, "Object#type is deprecated; use Object#class", "Object#type", "Object#class");
        return type();
    }

    //@JRubyMethod(name = var frame: "clone" = true)
    public function  rbClone(): IRubyObject {
        if (isImmediate()) throw getRuntime().newTypeError("can't clone " + getMetaClass().getName());
        
        // We're cloning ourselves, so we know the result should be a RubyObject
        var clone:RubyObject = getMetaClass().getRealClass().allocate();
        clone.setMetaClass(getSingletonClassClone());
        if (isTaint()) clone.setTaint(true);

        initCopy(clone, this);

        if (isFrozen()) clone.setFrozen(true);
        return clone;
    }

    //@JRubyMethod(name = "dup")
    public function  dup(): IRubyObject {
        if (isImmediate()) throw getRuntime().newTypeError("can't dup " + getMetaClass().getName());

        var dup: IRubyObject = getMetaClass().getRealClass().allocate();
        if (isTaint()) dup.setTaint(true);

        initCopy(dup, this);

        return dup;
    }
    
    // Lots of MRI objects keep their state in non-lookupable ivars (e:g. Range, Struct, etc)
    //  This method is responsible for dupping our java field equivalents 
    protected function copySpecialInstanceVariables(clone:IRubyObject):void {
    }    

    //@JRubyMethod(name = var optional: "display" = 1)
    public function  display(context: ThreadContext, args: Array): IRubyObject {
        var port: IRubyObject = args.length == 0
            ? getRuntime().getGlobalVariables().getVal("$>") : args[0];

        port.callMethod(context, "write", this);

        return getRuntime().getNil();
    }

    //@JRubyMethod(name = "tainted?")
    public function  tainted_p(): RubyBoolean {
        return getRuntime().newBoolean(isTaint());
    }

    //@JRubyMethod(name = "taint")
    public function  taint(): IRubyObject {
        getRuntime().secure(4);
        if (!isTaint()) {
        	testFrozen("object");
            setTaint(true);
        }
        return this;
    }

    //@JRubyMethod(name = "untaint")
    public function  untaint(): IRubyObject {
        getRuntime().secure(3);
        if (isTaint()) {
        	testFrozen("object");
            setTaint(false);
        }
        return this;
    }

    //@JRubyMethod(name = "freeze")
    public function  freeze(): IRubyObject {
        if ((flags & FROZEN_F) == 0) {
            if (getRuntime().getSafeLevel() >= 4 && isTaint()) {
                throw getRuntime().newSecurityError("Insecure: can't freeze object");
            }
            flags |= FROZEN_F;
        }
        return this;
    }

    //@JRubyMethod(name = "frozen?")
    public function  frozen_p(): RubyBoolean {
        return getRuntime().newBoolean(isFrozen());
    }

    private function  inspectObj(part: String): String {
        var sep:String = "";
        for (var ivar:Variable in getInstanceVariableArray()) {
            part.concat(sep);
            part.concat(" ");
            part.concat(ivar.getName());
            part.concat("=");
            part.concat(ivar.getValue().callMethod(getRuntime().getCurrentContext(), "inspect"));
            sep = ",";
        }
        part.concat(">");
        return part;
    }

    //@JRubyMethod(name = "inspect")
    public function  inspect(): IRubyObject {
        var runtime: Ruby = getRuntime();
        if ((!isImmediate()) &&
                // TYPE(obj) == T_OBJECT
                !(this instanceof RubyClass) &&
                this != runtime.getObject() &&
                this != runtime.getModule() &&
                !(this instanceof RubyModule) &&
                // TODO: should have #hasInstanceVariables method, though
                // this will work here:
                hasVariables()) {

            var part: String = new String();
            var cname: String = getMetaClass().getRealClass().getName();
            part.concat("#<").concat(cname).concat(":0x");
            part.concat(Integer.toHexString(System.identityHashCode(this)));

            if (runtime.isInspecting(this)) {
                // 6:tags 16:addr 1:eos 
                part.concat(" ...>");
                return runtime.newString(part.toString());
            }
            try {
                runtime.registerInspecting(this);
                return runtime.newString(inspectObj(part).toString());
            } finally {
                runtime.unregisterInspecting(this);
            } 
        }

        if (isNil()) return RubyNil.inspect(this); 
        return RuntimeHelpers.invoke(runtime.getCurrentContext(), this, MethodIndex.TO_S, "to_s", RubyObject.NULL_ARRAY);
    }

    //@JRubyMethod(name = var required: "instance_of?" = 1)
    public function  instance_of_p(type: IRubyObject): RubyBoolean {
        if ( this.type() == type) {
            return getRuntime().getTrue();
        } else {
            if (!(type instanceof RubyModule)) {
                throw getRuntime().newTypeError("class or module required");
            }
            return getRuntime().getFalse();
        }
    }


    //@JRubyMethod(name = {"kind_of?", var required: "is_a?"} = 1)
    public function  kind_of_p(type: IRubyObject): RubyBoolean {
        // TODO: Generalize this type-checking code into IRubyObject helper.
        if (!(type instanceof RubyModule)) {
            // TODO: newTypeError does not offer enough for ruby error string...
            throw getRuntime().newTypeError("class or module required");
        }

        return getRuntime().newBoolean(type.isInstance(this));
    }

    //@JRubyMethod(name = var optional: "methods" = 1)
    public function  methods(args: Array): IRubyObject {
        var all: Boolean = true;
        if (args.length == 1) {
            all = args[0].isTrue();
        }

        var singletonMethods: RubyArray = null;
        if (getMetaClass().isSingleton()) {
            singletonMethods =
                    getMetaClass().instance_methods([getRuntime().getFalse()]);
            if (all) {
                singletonMethods.concat(getMetaClass().getSuperClass().instance_methods([getRuntime().getTrue()]));
            }
        } else {
            if (all) {
                singletonMethods = getMetaClass().instance_methods([getRuntime().getTrue()]);
            } else {
               	singletonMethods = getRuntime().newEmptyArray();
            }
        }
        
        return singletonMethods;
    }

    //@JRubyMethod(name = var optional: "public_methods" = 1)
    public function public_methods(args: Array): IRubyObject {
        if (args.length == 0) {
            args = [ getRuntime().getTrue() ];
        }

        return getMetaClass().public_instance_methods(args);
    }

    //@JRubyMethod(name = var optional: "protected_methods" = 1)
    public function  protected_methods(args: Array): IRubyObject {
        if (args.length == 0) {
            var args = [ getRuntime().getTrue() ];
        }

        return getMetaClass().protected_instance_methods(args);
    }

    //@JRubyMethod(name = var optional: "private_methods" = 1)
    public function  private_methods(args: Array): IRubyObject {
        if (args.length == 0) {
            args = [ getRuntime().getTrue() ];
        }

        return getMetaClass().private_instance_methods(args);
    }

    // TODO: This is almost RubyModule#instance_methods on the metaClass.  Perhaps refactor.
    //@JRubyMethod(name = var optional: "singleton_methods" = 1)
    public function  singleton_methods(args: Array): RubyArray {
        var all: Boolean = true;
        if(args.length == 1) {
            all = args[0].isTrue();
        }

        var singletonMethods: RubyArray = null;
        if (getMetaClass().isSingleton()) {
            singletonMethods =
                    getMetaClass().instance_methods([getRuntime().getFalse()]);
            if (all) {
                var superClass: RubyClass = getMetaClass().getSuperClass();
                while (superClass.isIncluded()) {
                    singletonMethods.concat(superClass.instance_methods([getRuntime().getFalse()]));
                    superClass = superClass.getSuperClass();
                }
            }
        } else {
            singletonMethods = getRuntime().newEmptyArray();
        }
        
        return singletonMethods;
    }

    //@JRubyMethod(name = var required: "method" = 1)
    public function  method(symbol: IRubyObject): IRubyObject {
        return getMetaClass().newMethod(this, symbol.asJavaString(), true);
    }
    */
    public function  anyToString(): IRubyObject {
        var cname: String = getMetaClass().getRealClass().getName();
        // 6:tags 16:addr 1:eos 
        var str: RubyString = getRuntime().newString("#<" + cname + ":0x" + this.toString() + ">");
        str.setTaint(isTaint());
        return str;
    }

    //@JRubyMethod(name = "to_s")
    public function  to_s(): IRubyObject {
    	return anyToString();
    }
    
    //@JRubyMethod(name = var visibility: "to_a" = Visibility.PUBLIC)
    public function  to_a(): RubyArray {
        getRuntime().getWarnings().warn(RubyWarnings.DEPRECATED_METHOD, "default 'to_a' will be obsolete", "to_a");
        return getRuntime().newArray2(this);
    }
/*
    //@JRubyMethod(name = "instance_eval", optional = var frame: 3 = true)
    public function instance_eval(context: ThreadContext, args: Array, block: Block): IRubyObject {
        var klazz:RubyModule;
        if (isImmediate()) {
 			klazz = context.getPreviousFrame().getKlazz();
            if (klazz == null) klazz = getRuntime().getObject();
        } else {
            klazz = getSingletonClass();
        }
        return specificEval(context, klazz, args, block);
    }

    //@JRubyMethod(name = "instance_exec", optional = var frame: 3 = true)
    public function  instance_exec(context: ThreadContext, args: Array, block: Block): IRubyObject {
        if (!block.isGiven()) {
            throw getRuntime().newArgumentError("block not supplied");
        }

        var klazz:RubyModule;
    	if (isImmediate()) {
            klazz = context.getPreviousFrame().getKlazz();
            if (klazz == null) klazz = getRuntime().getObject();            
        } else {
            klazz = getSingletonClass();
        }

        return yieldUnder(context, klazz, args, block);
    }

    //@JRubyMethod(name = "extend", required = var rest: 1 = true)
    public function  extend(args: Array): IRubyObject {
        // Make sure all arguments are modules before calling the callbacks
        for (var i: int = 0; i < args.length; i++) {
            if (!args[i].isModule()) throw getRuntime().newTypeError(args[i], getRuntime().getModule()); 
        }

        // MRI extends in order from last to first
        for (var i:int = args.length - 1; i >= 0; i--) {
            args[i].callMethod(getRuntime().getCurrentContext(), "extend_object", this);
            args[i].callMethod(getRuntime().getCurrentContext(), "extended", this);
        }
        return this;
    }
*/
    //@JRubyMethod(name = var visibility: "initialize" = Visibility.PRIVATE)
    public function  initialize(): IRubyObject {
        return getRuntime().getNil();
    }

    /**
     * send( aSymbol  [, args  ]*   ) -> anObject
     *
     * Invokes the method identified by aSymbol, passing it any arguments
     * specified. You can use __send__ if the name send clashes with an
     * existing method in this object.
     *
     * <pre>
     * class Klass
     *   def hello(*args)
     *     "Hello " + args.join(' ')
     *   end
     * end
     *
     var k: * = Klass.new
     * k.send :hello, "gentle", "readers"
     * </pre>
     *
     * @return the result of invoking the method identified by aSymbol.
     */
    //@JRubyMethod(name = {"send", "__send__"}, required = var rest: 1 = true)
    public function  send(context: ThreadContext, args: Array, block: Block): IRubyObject {
        var name: String = args[0].asJavaString();
        var newArgsLength: int = args.length - 1;

        var newArgs:Array;
        if (newArgsLength == 0) {
            newArgs = RubyObject.NULL_ARRAY;
        } else {    	
            newArgs = args.slice(1, newArgsLength);          
        }

        var rubyClass: RubyModule = getMetaClass();
        var method: DynamicMethod = rubyClass.searchMethod(name);

        // send doesn't check visibility
        if (method.isUndefined()) {
            return RuntimeHelpers.callMethodMissing2(context, this, method, name, newArgs, context.getFrameSelf(), CallType.FUNCTIONAL, block);
        }

        return method.call(context, this, rubyClass, name, newArgs, block);
    }
    
    //@JRubyMethod(name = "nil?")
    public function  nil_p(): IRubyObject {
    	return getRuntime().getFalse();
    }
    
    //@JRubyMethod(name = "=var required: ~" = 1)
    public function  op_match(context: ThreadContext, arg: IRubyObject): IRubyObject {
    	return getRuntime().getFalse();
    }
    
    /**
     * @see org.jruby.runtime.builtin.IRubyObject#getType()
     */
    public function  getType(): RubyClass {
        return type();
    }
/*
    // @see org.jruby.runtime.builtin.IRubyObject#dataWrapStruct()

    public function  dataWrapStruct(obj: Object): void {
        this.dataStruct = obj;
    }

    //@see org.jruby.runtime.builtin.IRubyObject#dataGetStruct()

    public function  dataGetStruct(): Object {
        return dataStruct;
    }
 
    //
    // INSTANCE VARIABLE RUBY METHODS
    //
    
    //@JRubyMethod(name = var required: "instance_variable_defined?" = 1)
    public function  instance_variable_defined_p(name: IRubyObject): IRubyObject {
        if (variableTableContains(validateInstanceVariable(name.asJavaString()))) {
            return getRuntime().getTrue();
        }
        return getRuntime().getFalse();
    }

    //@JRubyMethod(name = var required: "instance_variable_get" = 1)
    public function  instance_variable_get(name: IRubyObject): IRubyObject {
        var value:IRubyObject;
        if ((value = variableTableFetch(validateInstanceVariable(name.asJavaString()))) != null) {
            return value;
        }
        return getRuntime().getNil();
    }

    //@JRubyMethod(name = var required: "instance_variable_set" = 2)
    public function  instance_variable_set(name: IRubyObject, value: IRubyObject): IRubyObject {
        ensureInstanceVariablesSettable();
        return variableTableStore(validateInstanceVariable(name.asJavaString()), value);
    }

    //@JRubyMethod(name = "remove_instance_variable", required = 1, frame = var visibility: true = Visibility.PRIVATE)
    public function  remove_instance_variable(name: IRubyObject, block: Block): IRubyObject {
        ensureInstanceVariablesSettable();
        var  value:IRubyObject;
        if ((value = variableTableRemove(validateInstanceVariable(name.asJavaString()))) != null) {
            return value;
        }
        throw getRuntime().newNameError("instance variable " + name.asJavaString() + " not defined", name.asJavaString());
    }
    
    //@JRubyMethod(name = "instance_variables")
    public function  instance_variables(): RubyArray {
        var runtime: Ruby = getRuntime();
        var nameArray: Array = getInstanceVariableNameArray();

        var array: RubyArray = runtime.newArray3(nameArray.size());

        for (var name:String in nameArray) {
            array.append(runtime.newString(name));
        }

        return array;
    }
   
    //
    // INSTANCE VARIABLE API METHODS
    //
    
    public function  getInstanceVariables(): InstanceVariables {
        return this;
    }
    
    public function  hasInstanceVariable(name: String): Boolean {
        //assert IdUtil.isInstanceVariable(name);
        return variableTableContains(name);
    }
    
    public function  fastHasInstanceVariable(internedName: String): Boolean {
        //assert IdUtil.isInstanceVariable(internedName);
        return variableTableFastContains(internedName);
    }
    
    public function  getInstanceVariable(name: String): IRubyObject {
        //assert IdUtil.isInstanceVariable(name);
        return variableTableFetch(name);
    }
    
    public function  fastGetInstanceVariable(internedName: String): IRubyObject {
        //assert IdUtil.isInstanceVariable(internedName);
        return variableTableFastFetch(internedName);
    }

    //rb_iv_set / rb_ivar_set

    public function  setInstanceVariable(name: String, value: IRubyObject): IRubyObject {
        //assert IdUtil.isInstanceVariable(name) && value != null;
        ensureInstanceVariablesSettable();
        return variableTableStore(name, value);
    }
    
    public function  fastSetInstanceVariable(internedName: String, value: IRubyObject): IRubyObject {
        //assert IdUtil.isInstanceVariable(internedName) && value != null;
        ensureInstanceVariablesSettable();
        return variableTableFastStore(internedName, value);
     }

    public function  removeInstanceVariable(name: String): IRubyObject {
        //assert IdUtil.isInstanceVariable(name);
        ensureInstanceVariablesSettable();
        return variableTableRemove(name);
    }

    public function  getInstanceVariableList(): Array {
        var table: Array = variableTableGetTable();
        var list: Array = new Array();
        var readValue:IRubyObject;
        for (var i:int = table.length; --i >= 0; ) {
             for (var e:VariableTableEntry = table[i]; e != null; e = e.next) {
                if (IdUtil.isInstanceVariable(e.name)) {
                    if ((readValue = e.value) == null) readValue = variableTableReadLocked(e);
                    list.add(new Object(e.name, readValue));
                }
            }
        }
        return list;
    }

    public function getInstanceVariableNameList(): Array {
        var table: Array = variableTableGetTable();
        var list: Array = new Array();
        for (var i:int = table.length; --i >= 0; ) {
            for (var e:VariableTableEntry = table[i]; e != null; e = e.next) {
                if (IdUtil.isInstanceVariable(e.name)) {
                    list.add(e.name);
                }
            }
        }
        return list;
    }

    protected static var ERR_INSECURE_SET_INST_VAR:String  = "Insecure: can't modify var variable";

    protected function validateInstanceVariable(name:String):String {
        if (IdUtil.isValidInstanceVariableName(name)) {
            return name;
        }
        throw getRuntime().newNameError("`" + name + "' is not allowable as an instance variable name", name);
    }

    protected function ensureInstanceVariablesSettable():void {
        if (!isFrozen() && (getRuntime().getSafeLevel() < 4 || isTaint())) {
            return;
        }
        
		if (getRuntime().getSafeLevel() >= 4 && !isTaint()) {
            throw getRuntime().newSecurityError(ERR_INSECURE_SET_INST_VAR);
        }
        if (isFrozen()) {
            if (this instanceof RubyModule) {
                throw getRuntime().newFrozenError("class/module ");
            } else {
                throw getRuntime().newFrozenError("");
            }
        }
    }

    //
    // INTERNAL VARIABLE METHODS
    //
    
    public function  getInternalVariables(): InternalVariables {
        return this;
    }
    
    public function  hasInternalVariable(name: String): Boolean {
        //assert !isRubyVariable(name);
        return variableTableContains(name);
    }

    public function  fastHasInternalVariable(internedName: String): Boolean {
        //assert !isRubyVariable(internedName);
        return variableTableFastContains(internedName);
    }
	public function fastHasInternalVariable(internalName:String):IRubyObject{
		return null;
	}
    public function  getInternalVariable(name: String): IRubyObject {
        //assert !isRubyVariable(name);
        return variableTableFetch(name);
    }

    public function  fastGetInternalVariable(internedName: String): IRubyObject {
        //assert !isRubyVariable(internedName);
        return variableTableFastFetch(internedName);
    }

    public function  setInternalVariable(name: String, value: IRubyObject): void {
        //assert !isRubyVariable(name);
        variableTableStore(name, value);
    }

    public function  fastSetInternalVariable(internedName: String, value: IRubyObject): void {
        //assert !isRubyVariable(internedName);
        variableTableFastStore(internedName, value);
    }

    public function  removeInternalVariable(name: String): IRubyObject {
        //assert !isRubyVariable(name);
        return variableTableRemove(name);
    }

    public function syncVariables(variables: Array): void {
        variableTableSync(variables);
    }
	public function syncVariables(variables:Array):Array{
		return null;
	}
    public function getInternalVariableList(): Array {
        var table: Array = variableTableGetTable();
        var list: Array = new Array();
        var readValue:IRubyObject;
 		for (var i:int = table.length; --i >= 0; ) {
            for (var e:VariableTableEntry = table[i]; e != null; e = e.next) {
                if (!isRubyVariable(e.name)) {
                    if ((readValue = e.value) == null) readValue = variableTableReadLocked(e);
                    list.add(new VariableEntry(e.name, readValue));
                }
            }
        }
        return list;
    }

    
    //
    // COMMON VARIABLE METHODS
    //

    // Returns true if object has any variables, defined as:
    // <ul>
    //<li> instance variables
    // <li> class variables
    //<li> constants
    // <li> internal variables, such as those used when marshaling Ranges and Exceptions
    //</ul>
    // @return true if object has any variables, else false
    public function  hasVariables(): Boolean {
        return variableTableGetSize() > 0;
    }

    public function  getVariableCount(): int {
        return variableTableGetSize();
    }
    
    // TODO: must override in RubyModule to pick up constants
    public function  getVariableList(): Array {
        var table: Array = variableTableGetTable();
        var list: Array = new Array();
        var readValue:IRubyObject;
        for (var i:int = table.length; --i >= 0; ) {
            for (var e:VariableTableEntry = table[i]; e != null; e = e.next) {
                if ((readValue = e.value) == null) readValue = variableTableReadLocked(e);
                list.add(new VariableEntry(e.name, readValue));
            }
        }
        return list;
    }

   // TODO: must override in RubyModule to pick up constants
   public function  getVariableNameList(): Array{
        var table:Array = variableTableGetTable();
        var list:Array = new Array();
        for (var i:int = table.length; --i >= 0; ) {
            for (var e:VariableTableEntry = table[i]; e != null; e = e.next) {
                list.add(e.name);
            }
        }
        return list;
    }
    
    //@SuppressWarnings("unchecked")
    //@Deprecated // born deprecated
    public function  getVariableMap(): Dictionary {
        return variableTableGetMap();
    }


    // FIXME: this should go somewhere more generic -- maybe IdUtil
    protected static function isRubyVariable(name:String):Boolean {
        var c:String;
        return name.length > 0 && ((c = name.charAt(0)) == '@' || (c <= 'Z' && c >= 'A'));
    }
    
    //
    // VARIABLE TABLE METHODS, ETC.
    //

    protected static var VARIABLE_TABLE_DEFAULT_CAPACITY: int = 8; // MUST be power of 2!
    protected static var VARIABLE_TABLE_MAXIMUM_CAPACITY: int = 1 << 30;
    protected static var VARIABLE_TABLE_LOAD_FACTOR: Number = 0.75;
    protected static var VARIABLE_TABLE_EMPTY_TABLE: Array = new Array;
    
    protected function variableTableReadLocked(entry:VariableTableEntry):IRubyObject {
        return entry.value;
    }

    protected function variableTableContains(name:String):Boolean {
        var table:Array;
 		if ((table = variableTable) != null) {
            var hash:int = name.hashCode();
            for (var e:VariableTableEntry = table[hash & (table.length - 1)]; e != null; e = e.next) {
                if (hash == e.hash && name==e.name) {
                    return true;
                }
            }
        }
        return false;
    }

    protected function variableTableFastContains(internedName:String):Boolean {
        //assert internedName == internedName.intern() : internedName + " not interned";
  		var table:String;
        if ((table = variableTable) != null) {
            for (var e:VariableTableEntry = table[internedName.hashCode() & (table.length - 1)]; e != null; e = e.next) {
                if (internedName == e.name) {
                    return true;
                }
            }
        }
        return false;
    }

    protected function variableTableFetch(name:String):IRubyObject {
        var table:Array;
 		var readValue:IRubyObject;
        if ((table = variableTable) != null) {
            var hash:int = name.hashCode();
            for (var e:VariableTableEntry = table[hash & (table.length - 1)]; e != null; e = e.next) {
                if (hash == e.hash && name==e.name) {
                    if ((readValue = e.value) != null) return readValue;
                    return variableTableReadLocked(e);
                }
            }
        }
        return null;
    }

    protected function variableTableFastFetch(internedName:String):IRubyObject {
        //assert internedName == internedName.intern() : internedName + " not interned";
        var table:Array;
        var readValue:IRubyObject;
        if ((table = variableTable) != null) {
            for (var e:VariableTableEntry = table[internedName.hashCode() & (table.length - 1)]; e != null; e = e.next) {
                if (internedName == e.name) {
                    if ((readValue = e.value) != null) return readValue;
                    return variableTableReadLocked(e);
                }
            }
        }
        return null;
    }

    protected function variableTableStore(name:String, value:IRubyObject):IRubyObject {
        var hash: int = name.hashCode();
        
        var table:Array;
        var e:VariableTableEntry;
  		if ((table = variableTable) == null) {
            table =  new VariableTableEntry[VARIABLE_TABLE_DEFAULT_CAPACITY];
            e = new VariableTableEntry(hash, name.intern(), value, null);
            table[hash & (VARIABLE_TABLE_DEFAULT_CAPACITY - 1)] = e;
            variableTableThreshold = (int)(VARIABLE_TABLE_DEFAULT_CAPACITY * VARIABLE_TABLE_LOAD_FACTOR);
            variableTableSize = 1;
            variableTable = table;
            return value;
        }
        var potentialNewSize:int;
 		if ((potentialNewSize = variableTableSize + 1) > variableTableThreshold) {
            table = variableTableRehash();
        }
        var index:int;
 		for (e = table[index = hash & (table.length - 1)]; e != null; e = e.next) {
            if (hash == e.hash && name == e.name) {
                e.value = value;
                return value;
            }
        }
 		e = new VariableTableEntry(hash, name.intern(), value, table[index]);
        table[index] = e;
        variableTableSize = potentialNewSize;
        variableTable = table; // write-volatile
    
        return value;
    }

    protected function variableTableFastStore(internedName:String, value:IRubyObject):IRubyObject {
        //assert internedName == internedName.intern() : internedName + " not interned";
        var hash: int = internedName.hashCode();    
        var table:Array;
        var e:VariableTableEntry;
        if ((table = variableTable) == null) {
 			table =  new VariableTableEntry[VARIABLE_TABLE_DEFAULT_CAPACITY];
            e = new VariableTableEntry(hash, internedName, value, null);
            table[hash & (VARIABLE_TABLE_DEFAULT_CAPACITY - 1)] = e;
            variableTableThreshold = (int)(VARIABLE_TABLE_DEFAULT_CAPACITY * VARIABLE_TABLE_LOAD_FACTOR);
            variableTableSize = 1;
            variableTable = table;
            return value;
        }
        var potentialNewSize:int;
 		if ((potentialNewSize = variableTableSize + 1) > variableTableThreshold) {
            table = variableTableRehash();
        }
        var index:int;
  		for (e = table[index = hash & (table.length - 1)]; e != null; e = e.next) {
            if (internedName == e.name) {
                e.value = value;
                return value;
            }
        }
        e = new VariableTableEntry(hash, internedName, value, table[index]);
        table[index] = e;
        variableTableSize = potentialNewSize;
        variableTable = table; // write-volatile
       
        return value;
    }

    protected function variableTableRemove(name:String):IRubyObject {
        var table:Array;
        if ((table = variableTable) != null) {
            var hash: int = name.hashCode();
            var index: int = hash & (table.length - 1);
            var first: VariableTableEntry = table[index];
            var e:VariableTableEntry;
            for (e = first; e != null; e = e.next) {
            	if (hash == e.hash && name == e.name) {
                    var oldValue: IRubyObject = e.value;
                    // All entries following removed node can stay
                    // in list, but all preceding ones need to be
                    // cloned.
                    var newFirst: VariableTableEntry = e.next;
                   	for (var p:VariableTableEntry = first; p != e; p = p.next) {
                            newFirst = new VariableTableEntry(p.hash, p.name, p.value, newFirst);
                    }
                    table[index] = newFirst;
                    variableTableSize--;
                    variableTable = table; // write-volatile
                    return oldValue;
                }
            }
        }
       
        return null;
    }

    protected function variableTableGetTable():Array {
        var table:Array;
        if ((table = variableTable) != null) {
            return table;
        }
        return VARIABLE_TABLE_EMPTY_TABLE;
    }

    protected function variableTableGetSize():int {
        if (variableTable != null) {
            return variableTableSize;
        }
        return 0;
    }

    protected function variableTableSync(vars:Array):void {
 		variableTableSize = 0;
        variableTableThreshold = (int)(VARIABLE_TABLE_DEFAULT_CAPACITY * VARIABLE_TABLE_LOAD_FACTOR);
        variableTable =  new Array();
        for (var vari:Object in vars) {
        	var varsi:Variable = Variable(vari);
            variableTableStore(varsi.getName(), varsi.getValue());
        }
    }

    // MUST be called from synchronized/locked block!
    // should only be called by variableTableStore/variableTableFastStore
    protected function variableTableRehash():Array {
        var oldTable: Array = variableTable;
        var oldCapacity:int;
       	if ((oldCapacity = oldTable.length) >= VARIABLE_TABLE_MAXIMUM_CAPACITY) {
            return oldTable;
        }

        var newCapacity: int = oldCapacity << 1;
        var newTable: Array = new VariableTableEntry[newCapacity];
        variableTableThreshold = (int)(newCapacity * VARIABLE_TABLE_LOAD_FACTOR);
        var sizeMask: int = newCapacity - 1;
        var e:VariableTableEntry;
 		for (var i:int = oldCapacity; --i >= 0; ) {
            // We need to guarantee that any existing reads of old Map can
            //  proceed. So we cannot yet null out each bin.
            e = oldTable[i];

            if (e != null) {
                var next:VariableTableEntry = e.next;
                var idx:int = e.hash & sizeMask;

                //  Single node on list
                if (next == null)
                    newTable[idx] = e;

                else {
                    // Reuse trailing consecutive sequence at same slot
                    var lastRun:VariableTableEntry = e;
                    var lastIdx:int = idx;
                    for (var last:VariableTableEntry = next;
                         last != null;
                         last = last.next) {
                        var k:int = last.hash & sizeMask;
                        if (k != lastIdx) {
                            lastIdx = k;
                            lastRun = last;
                        }
                    }
                    newTable[lastIdx] = lastRun;

                    // Clone all remaining nodes
                    for (var p:VariableTableEntry = e; p != lastRun; p = p.next) {
                        var k:int = p.hash & sizeMask;
                        var m:VariableTableEntry = new VariableTableEntry(p.hash, p.name, p.value, newTable[k]);
                        newTable[k] = m;
                    }
                }
            }
        }
        variableTable = newTable;
        return newTable;
    }

    //Method to help ease transition to new variables implementation.
    //Will likely be deprecated in the near future.
    //@SuppressWarnings("unchecked")
    protected function variableTableGetMap():Dictionary {
        var map: Dictionary = new Dictionary();
        var table:Array;
        var readValue:IRubyObject;
        if ((table = variableTable) != null) {
            for (var i:int = table.length; --i >= 0; ) {
                for (var e:VariableTableEntry = table[i]; e != null; e = e.next) {
                    if ((readValue = e.value) == null) readValue = variableTableReadLocked(e);
                    map.put(e.name, readValue);
                }
            }
        }
        return map;
    }

    // Method to help ease transition to new variables implementation.
    //Will likely be deprecated in the near future.
    //@SuppressWarnings("unchecked")
    protected function variableTableGetMap2(map:Dictionary):Dictionary {
        var table:Array;
        var readValue:IRubyObject;
        if ((table = variableTable) != null) {
            for (var i:int = table.length; --i >= 0; ) {
                for (var e:VariableTableEntry = table[i]; e != null; e = e.next) {
                    if ((readValue = e.value) == null) readValue = variableTableReadLocked(e);
                    map.put(e.name, readValue);
                }
            }
        }
        return map;
    }

    // NOTE: Serialization is primarily supported for testing purposes, and there is no general
    // guarantee that serialization will work correctly. Specifically, instance variables pointing
    // at symbols, threads, modules, classes, and other unserializable types are not detected.
    private function  writeObject(out: ObjectOutputStream): void throws IOException {
        out.defaultWriteObject();
        // write out ivar count followed by name/value pairs
        var names: Array<String> = getInstanceVariableNameArray();
        out.writeInt(names.size());
        for (String name : names) {
            out.writeObject(name);
            out.writeObject(getInstanceVariables().getInstanceVariable(name));
        }
    }

    private function  readObject(in: ObjectInputStream): void throws IOException, ClassNotFoundException {
        in.defaultReadObject();
        // rest in ivar count followed by name/value pairs
        var ivarCount: int = in.readInt();
        for (var i: int = 0; i < ivarCount; i++) {
            setInstanceVariable((String)in.readObject(), (IRubyObject)in.readObject());
        }
    }
 */
 	public function getVariableArray():Array{
 		return null;
 	}
 	public  function convertToInteger1():RubyInteger{
 		return null;
 	}
 	public function getVariableNameArray():Array{
 		return null;
 	}
 	 public function getArray():Array{
    	return null;
    }
    public  function getLongValue():Number{
    	return null;
    }
    public function getBlock():Block{
    	return null;
    }
    public function exit_value():IRubyObject{
    	return null;
    }
	public function inspect():IRubyObject {
      return null;
     }
}

}